package com.ruoyi.quartz.task;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Calendar; // 添加Calendar导入
import java.net.InetAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.MeterData;
import com.ruoyi.system.service.IMeterDataService;

// 使用j2mod库的导入
import com.ghgande.j2mod.modbus.ModbusException;
import com.ghgande.j2mod.modbus.io.ModbusTransaction;
import com.ghgande.j2mod.modbus.io.ModbusTCPTransaction; // 添加这一行
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersRequest;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersResponse;
import com.ghgande.j2mod.modbus.net.TCPMasterConnection;
import com.ghgande.j2mod.modbus.procimg.Register;

/**
 * Modbus TCP数据采集定时任务 (使用j2mod库实现)
 * 
 * @author ruoyi
 */
@Component("modbusTcpTask")
public class ModbusTcpCollectTask {
    private static final Logger log = LoggerFactory.getLogger(ModbusTcpCollectTask.class);
    
    @Autowired
    private IMeterDataService meterDataService;
    
    
    /**
     * 使用Modbus RTU over TCP协议采集电表数据
     */
    public void collectFromGateway(String ip, Integer port, String deviceId) {

        MeterData meterData = new MeterData();
        meterData.setDeviceId(deviceId);
        Date collectTime = DateUtils.getNowDate();
        meterData.setCollectTime(collectTime);
        
        // 设置timePoint为当前小时数
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(collectTime);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        meterData.setTimePoint(hour);
        
        meterData.setStatus(1); // 默认设置为正常状态
        
        TCPMasterConnection connection = null;
        try {
            // 创建并打开Modbus RTU over TCP连接
            connection = getMaster(ip, port);
            log.info("连接成功，Modbus RTU over TCP连接已初始化");
            
            // 读取电表数据
            int slaveId = 1; // 从站ID，根据实际情况调整
            
            // 读取Ua - 地址32768
            try {
                float ua = readFloat(connection, slaveId, 32768);
                meterData.setUa((Double)((double)ua)); // 转换为Double类型
            } catch (Exception e) {
                log.error("读取Ua失败: " + e.getMessage());
            }
            
            // 读取Ub - 地址32770
            try {
                float ub = readFloat(connection, slaveId, 32770);
                meterData.setUb((Double)((double)ub)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Ub失败: " + e.getMessage());
            }
            
            // 读取Uc - 地址32772
            try {
                float uc = readFloat(connection, slaveId, 32772);
                meterData.setUc((Double)((double)uc)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Uc失败: " + e.getMessage());
            }
            
            // 读取Uab - 地址32774
            try {
                float uab = readFloat(connection, slaveId, 32774);
                meterData.setUab((Double)((double)uab)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Uab失败: " + e.getMessage());
            }
            
            // 读取Ubc - 地址32776
            try {
                float ubc = readFloat(connection, slaveId, 32776);
                meterData.setUbc((Double)((double)ubc)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Ubc失败: " + e.getMessage());
            }
            
            // 读取Uca - 地址32778
            try {
                float uca = readFloat(connection, slaveId, 32778);
                meterData.setUca((Double)((double)uca)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Uca失败: " + e.getMessage());
            }
            
            // 读取Ia - 地址32780
            try {
                float ia = readFloat(connection, slaveId, 32780);
                meterData.setIa((Double)((double)ia)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Ia失败: " + e.getMessage());
            }
            
            // 读取Ib - 地址32782
            try {
                float ib = readFloat(connection, slaveId, 32782);
                meterData.setIb((Double)((double)ib)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Ib失败: " + e.getMessage());
            }
            
            // 读取Ic - 地址32784
            try {
                float ic = readFloat(connection, slaveId, 32784);
                meterData.setIc((Double)((double)ic)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Ic失败: " + e.getMessage());
            }
            
            // 读取Pt - 地址32794
            try {
                float pt = readFloat(connection, slaveId, 32794);
                meterData.setPt((Double)((double)pt)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Pt失败: " + e.getMessage());
            }
            
            // 读取Qt - 地址32802
            try {
                float qt = readFloat(connection, slaveId, 32802);
                meterData.setQt((Double)((double)qt)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Qt失败: " + e.getMessage());
            }
            
            // 读取Pf - 地址32818
            try {
                float pf = readFloat(connection, slaveId, 32818);
                meterData.setPf((Double)((double)pf)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Pf失败: " + e.getMessage());
            }
            
            // 读取Freq - 地址32820
            try {
                float freq = readFloat(connection, slaveId, 32820);
                meterData.setFreq((Double)((double)freq)); // 转换为Double类型
            } catch (Exception e) {
                System.out.println("读取Freq失败: " + e.getMessage());
            }
            
            // 读取TotalActiveEnergy - 地址34942
            try {
                double totalActiveEnergy = readFloat(connection, slaveId, 34942);
                meterData.setTotalActiveEnergy(totalActiveEnergy);
            } catch (Exception e) {
                System.out.println("读取TotalActiveEnergy失败: " + e.getMessage());
            }
            
            System.out.println("电表数据采集成功");
            
        } catch (Exception e) {
            System.out.println("采集电表数据时发生错误: " + e.getMessage());
            e.printStackTrace();
            meterData.setStatus(0); // 设置为异常状态
            meterData.setRemark("采集错误: " + e.getMessage());
        } finally {
            // 关闭连接并释放资源
            if (connection != null) {
                try {
                    // 关闭连接
                    connection.close();
                    System.out.println("Modbus连接已关闭");
                } catch (Exception e) {
                    System.out.println("关闭Modbus连接时发生错误: " + e.getMessage());
                }
            }
        }
        
        // 保存采集的数据
        try {
            meterDataService.insertMeterData(meterData);
        } catch (Exception e) {
            System.out.println("保存电表数据时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 读取浮点数值（占用2个寄存器）
     * 
     * @param connection Modbus TCP连接
     * @param slaveId 从站ID
     * @param address 寄存器地址
     * @return 浮点数值
     * @throws ModbusException
     */
    /**
     * 读取浮点数值（占用2个寄存器）
     * 
     * @param connection Modbus TCP连接
     * @param slaveId 从站ID
     * @param address 寄存器地址
     * @return 浮点数值
     * @throws ModbusException
     */
    public float readFloat(TCPMasterConnection connection, int slaveId, int address) throws ModbusException {
        // 创建读取请求
        ReadMultipleRegistersRequest request = new ReadMultipleRegistersRequest(address, 2);
        request.setUnitID(slaveId);
        
        // 创建Modbus事务 - 修改这里，直接使用ModbusTCPTransaction
        ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection);
        transaction.setRequest(request);
        transaction.execute();
        
        // 获取响应
        ReadMultipleRegistersResponse response = (ReadMultipleRegistersResponse) transaction.getResponse();
        
        // 获取寄存器值
        Register[] registers = response.getRegisters();
        
        // 使用ABCD字节顺序
        int bitsABCD = ((registers[0].getValue() & 0xFFFF) << 16) | (registers[1].getValue() & 0xFFFF);
        float valueABCD = Float.intBitsToFloat(bitsABCD);
        
        return valueABCD;
    }
    
    /**
     * 读取双精度浮点数值（占用4个寄存器）
     * 
     * @param connection Modbus TCP连接
     * @param slaveId 从站ID
     * @param address 寄存器地址
     * @return 双精度浮点数值
     * @throws ModbusException
     */
    /**
     * 读取双精度浮点数值（占用4个寄存器）
     * 
     * @param connection Modbus TCP连接
     * @param slaveId 从站ID
     * @param address 寄存器地址
     * @return 双精度浮点数值
     * @throws ModbusException
     */
    public double readDouble(TCPMasterConnection connection, int slaveId, int address) throws ModbusException {
        // 创建读取请求
        ReadMultipleRegistersRequest request = new ReadMultipleRegistersRequest(address, 4);
        request.setUnitID(slaveId);
        
        // 创建Modbus事务 - 修改这里，直接使用ModbusTCPTransaction
        ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection);
        transaction.setRequest(request);
        transaction.execute();
        
        // 获取响应
        ReadMultipleRegistersResponse response = (ReadMultipleRegistersResponse) transaction.getResponse();
        
        // 获取寄存器值
        Register[] registers = response.getRegisters();
        
        // 将四个16位寄存器值转换为64位双精度浮点数
        long bits = ((long)(registers[0].getValue() & 0xFFFF) << 48) | 
                   ((long)(registers[1].getValue() & 0xFFFF) << 32) | 
                   ((long)(registers[2].getValue() & 0xFFFF) << 16) | 
                   (registers[3].getValue() & 0xFFFF);
        return Double.longBitsToDouble(bits);
    }

    /**
     * 获取ModbusMaster实例
     * 
     * @param ip IP地址
     * @param port 端口
     * @return TCPMasterConnection实例
     * @throws Exception 初始化异常
     */
    private TCPMasterConnection getMaster(String ip, int port) throws Exception {
        InetAddress addr = InetAddress.getByName(ip);
        TCPMasterConnection connection = new TCPMasterConnection(addr);
        connection.setPort(port);
        
        // 设置为RTU over TCP模式
        connection.setUseRtuOverTcp(true);
        
        // 设置超时和重试次数
        connection.setTimeout(10000); // 10秒超时
        
        // 连接到设备
        connection.connect();
        return connection;
    }

}